Skip to content

Add explicit SSH public key configuration support#348

Open
sayalibhavsar wants to merge 2 commits intomainfrom
gh-323
Open

Add explicit SSH public key configuration support#348
sayalibhavsar wants to merge 2 commits intomainfrom
gh-323

Conversation

@sayalibhavsar
Copy link
Contributor

@sayalibhavsar sayalibhavsar commented Feb 3, 2026

Description

Add --ssh_public_key_file CLI option to bin/burden and a ssh_public_key_path Terraform variable across AWS, Azure, and GCP so users can specify public and private SSH keys independently
instead of relying on hardcoded or .pub-derived paths.

Before/After Comparison

Before: Public key hardcoded to ~/.ssh/id_rsa.pub (Azure) or derived by appending .pub to the private key path (GCP); no way to specify a separate public key.

After: New --ssh_public_key_file option and ssh_public_key_path variable let users set the public key path explicitly; defaults to ~/.ssh/id_rsa.pub for backward compatibility.

Documentation Check

No updates needed — optional flag with a backward-compatible default.

Clerical Stuff

This closes #227
Relates to JIRA: RPOPC-492

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 3, 2026

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟡
🎫 #323
🔴 During installation, check whether `/home/uploads` exists.
If /home/uploads is missing, print a non-blocking warning: Warning: /home/uploads
directory not found. Some wrappers may fail until it is created.
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

🔴
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Silent yq failures: The new kit-directory validation swallows yq parsing/command errors (redirecting stderr
and defaulting to "none"), which can silently skip validation and provides no
actionable error context when yq is missing or templates are invalid.

Referred Code
# Extract upload_extra value using yq
upload_extra=$(yq -r '.upload_extra // "none"' "$template_file" 2>/dev/null || echo "none")

# Skip if upload_extra is 'none', empty, or null
if [[ "$upload_extra" == "none" ]] || [[ -z "$upload_extra" ]] || [[ "$upload_extra" == "null" ]]; then
    continue
fi

# Check if upload_extra is an array or a string
is_array=$(yq -r '.upload_extra | type' "$template_file" 2>/dev/null || echo "null")

if [[ "$is_array" == "array" ]]; then
    # It's an array, process each element
    while IFS= read -r path; do
        if [[ "$path" != "none" ]] && [[ -n "$path" ]]; then
            if [[ ! -e "$path" ]]; then
                missing_kits+=("$template_name:$path")
            fi
        fi
    done < <(yq -r '.upload_extra[]' "$template_file" 2>/dev/null)
else

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Missing default propagation: When --ssh_key_file is provided but --ssh_public_key_file is not, the PR omits writing
ssh_public_key into ansible_vars_main.yml, which may cause downstream Terraform templating
(config_info.ssh_public_key) to be unset and fail depending on unseen defaults.

Referred Code
if [[ $gl_ssh_key_file == "" ]]; then
	echo "  ssh_key: $HOME/.ssh/id_rsa" >> ansible_vars_main.yml
	echo "  ssh_public_key: $HOME/.ssh/id_rsa.pub" >> ansible_vars_main.yml
else
	echo "  ssh_key: ${gl_ssh_key_file}" >> ansible_vars_main.yml
	if [[ $gl_ssh_public_key_file != "" ]]; then
		echo "  ssh_public_key: ${gl_ssh_public_key_file}" >> ansible_vars_main.yml
	fi
fi

Learn more about managing compliance generic rules or creating your own custom rules

  • Update
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 3, 2026

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Fix missing public key path

In bin/burden, if a user provides a private key but not a public key,
automatically derive the public key path by appending .pub to the private key
path to prevent Terraform failures.

bin/burden [1911-1919]

 		if [[ $gl_ssh_key_file == "" ]]; then
 			echo "  ssh_key: $HOME/.ssh/id_rsa" >> ansible_vars_main.yml
 			echo "  ssh_public_key: $HOME/.ssh/id_rsa.pub" >> ansible_vars_main.yml
 		else
 			echo "  ssh_key: ${gl_ssh_key_file}" >> ansible_vars_main.yml
 			if [[ $gl_ssh_public_key_file != "" ]]; then
 				echo "  ssh_public_key: ${gl_ssh_public_key_file}" >> ansible_vars_main.yml
+			else
+				echo "  ssh_public_key: ${gl_ssh_key_file}.pub" >> ansible_vars_main.yml
 			fi
 		fi
  • Apply / Chat
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical bug where the public key path is not set if only a private key is provided, which would cause Terraform to fail.

High
General
Consolidate duplicate file verification functions

In bin/burden, consolidate the duplicate verify_ssh_key_file and
verify_ssh_public_key_file functions into a single, generic function that
accepts a file path and description.

bin/burden [2351-2363]

-verify_ssh_key_file()
+verify_file_exists()
 {
-	if [[ ! -f $1 ]]; then
-		cleanup_and_exit "Error: ssh key file $1 does not exist." 1
+	local file_path="$1"
+	local file_description="$2"
+	if [[ ! -f "$file_path" ]]; then
+		cleanup_and_exit "Error: $file_description file '$file_path' does not exist." 1
 	fi
 }
 
-verify_ssh_public_key_file()
-{
-	if [[ ! -f $1 ]]; then
-		cleanup_and_exit "Error: ssh public key file $1 does not exist." 1
-	fi
-}
-

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies code duplication and proposes a good refactoring to improve maintainability, which is a valid but moderate-impact improvement.

Low
  • Update

@sayalibhavsar sayalibhavsar force-pushed the gh-323 branch 2 times, most recently from 80b034f to fb414d6 Compare February 3, 2026 18:38
@sayalibhavsar
Copy link
Contributor Author

sayalibhavsar commented Feb 3, 2026

The removal of the auto-derivation (${gl_ssh_key_file}.pub) is intentional, not a flaw. Users should explicitly specify the public key path when needed for provisioning scenarios, rather than having it automatically derived.

Test Results: https://gist.github.com/sayalibhavsar/236e35ee79ec92b36ef02f71cc497a05

@sayalibhavsar sayalibhavsar self-assigned this Feb 17, 2026
@github-actions
Copy link

PullHero Review

Provider: generativelanguage.googleapis.com Model: gemini-2.0-flash

Okay, I've reviewed the changes. Here's my assessment:

Overview

This PR introduces the ability to specify a separate SSH public key file. Currently, the code assumes the public key is located at ~/.ssh/id_rsa.pub based on the private key specified, but this change allows for greater flexibility in key management by explicitly defining the public key path.

Analysis

Code Quality and Maintainability:

  • The code is generally well-structured and easy to follow.
  • The addition of a new global variable (gl_ssh_public_key_file) and corresponding functions (verify_ssh_public_key_file, set_general_value) is a clean and logical extension of the existing framework.
  • The modifications to the Terraform template files (tfvars.j2) are straightforward and maintain consistency.

Potential Bugs or Security Issues:

  • It is important to consider if the tool should verify that the public key actually corresponds to the private key. While this adds complexity, it could prevent misconfiguration where the wrong public key is used. The current code trusts that the user provides the correct key pair.
  • The code adds a new parameter, but doesn't enforce its use, meaning the old behavior persists. This may or may not be desired, but should be explicitly documented.

Adherence to Project Conventions:

  • The changes seem to follow the established coding style and conventions of the project.
  • The introduction of the new option (--ssh_public_key_file) is consistent with the existing CLI option structure.

Documentation Completeness:

  • The bin/burden usage output has been updated to include the new option, which is good.
  • The docs/command_line_reference.md file needs to be updated to reflect the new command line option and explain its usage.
  • The documentation should clearly state that if --ssh_public_key_file is not specified, the tool defaults to assuming the public key is located at ~/.ssh/id_rsa.pub (based on ssh_key_path).
  • The documentation should discuss the security implications of using separate public and private key files.

Specific Feedback:

  • Recommendation: Add a check to verify_ssh_public_key_file to ensure the file is readable and contains a valid public key format.
  • Suggestion: Consider adding a warning message if only --ssh_key_file is provided, reminding the user of the default public key path assumption.
  • Suggestion: Add a check in create_ansible_options() to verify if gl_ssh_public_key_file is set, if it's not, then fall back to the default assumption ssh_public_key: $HOME/.ssh/id_rsa.pub so that the ansible code can use it.
  • Improvement: Update docs/command_line_reference.md to fully document the new option with examples.

Vote: -1

The code itself is good, however, documentation needs to be updated to reflect the changes. Additionally, it would be better to have a check to make sure the user is providing a valid public key file.

Vote: -1

PullHero

@github-actions
Copy link

This relates to RPOPC-492

@kdvalin
Copy link
Member

kdvalin commented Feb 17, 2026

Want output from a uperf run; verify this does not break old scenario files, provide output

@sayalibhavsar sayalibhavsar deleted the gh-323 branch February 24, 2026 16:41
@sayalibhavsar sayalibhavsar reopened this Feb 27, 2026
@qodo-code-review
Copy link

Review Summary by Qodo

Add explicit SSH public key configuration support across cloud providers

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add --ssh_public_key_file CLI option to bin/burden for explicit SSH public key configuration
• Introduce ssh_public_key_path Terraform variable across AWS, Azure, and GCP providers
• Replace hardcoded public key paths with configurable variable references
• Maintain backward compatibility with default ~/.ssh/id_rsa.pub path
Diagram
flowchart LR
  CLI["CLI Option<br/>--ssh_public_key_file"]
  BURDEN["bin/burden<br/>Script"]
  ANSIBLE["Ansible Variables<br/>ssh_public_key"]
  TF["Terraform Variables<br/>ssh_public_key_path"]
  CLOUDS["Cloud Providers<br/>AWS/Azure/GCP"]
  
  CLI -->|"Parsed by"| BURDEN
  BURDEN -->|"Generates"| ANSIBLE
  ANSIBLE -->|"Passed to"| TF
  TF -->|"Configures"| CLOUDS
Loading

Grey Divider

File Changes

1. bin/burden ✨ Enhancement +23/-1

Add SSH public key CLI option and validation

bin/burden


2. ansible_roles/roles/aws_create/files/tf/vars.tf ✨ Enhancement +5/-0

Add ssh_public_key_path Terraform variable

ansible_roles/roles/aws_create/files/tf/vars.tf


3. ansible_roles/roles/aws_create/templates/tfvars.j2 ✨ Enhancement +1/-0

Pass SSH public key path to Terraform

ansible_roles/roles/aws_create/templates/tfvars.j2


View more (9)
4. ansible_roles/roles/azure_create/files/tf/vars.tf ✨ Enhancement +5/-0

Add ssh_public_key_path Terraform variable

ansible_roles/roles/azure_create/files/tf/vars.tf


5. ansible_roles/roles/azure_create/files/tf/main_net_p2_sub.tf ✨ Enhancement +1/-1

Replace hardcoded public key with variable

ansible_roles/roles/azure_create/files/tf/main_net_p2_sub.tf


6. ansible_roles/roles/azure_create/files/tf/main_net_p2_urn.tf ✨ Enhancement +1/-1

Replace hardcoded public key with variable

ansible_roles/roles/azure_create/files/tf/main_net_p2_urn.tf


7. ansible_roles/roles/azure_create/files/tf/vm_spot_set_sub.tf ✨ Enhancement +1/-1

Replace hardcoded public key with variable

ansible_roles/roles/azure_create/files/tf/vm_spot_set_sub.tf


8. ansible_roles/roles/azure_create/files/tf/vm_spot_set_urn.tf ✨ Enhancement +1/-1

Replace hardcoded public key with variable

ansible_roles/roles/azure_create/files/tf/vm_spot_set_urn.tf


9. ansible_roles/roles/azure_create/templates/tfvars.j2 ✨ Enhancement +1/-0

Pass SSH public key path to Terraform

ansible_roles/roles/azure_create/templates/tfvars.j2


10. ansible_roles/roles/gcp_create_instance/files/tf/vars.tf ✨ Enhancement +5/-0

Add ssh_public_key_path Terraform variable

ansible_roles/roles/gcp_create_instance/files/tf/vars.tf


11. ansible_roles/roles/gcp_create_instance/files/tf/main.tf ✨ Enhancement +1/-1

Replace derived public key with variable

ansible_roles/roles/gcp_create_instance/files/tf/main.tf


12. ansible_roles/roles/gcp_create_instance/templates/tfvars.j2 ✨ Enhancement +1/-0

Pass SSH public key path to Terraform

ansible_roles/roles/gcp_create_instance/templates/tfvars.j2


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 27, 2026

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (1)

Grey Divider


Action required

1. --ssh_public_key_file ignored📎 Requirement gap ✓ Correctness
Description
When --ssh_key_file is not provided, the code always writes a default ssh_public_key value and
ignores a user-supplied --ssh_public_key_file. This prevents independently specifying the public
key and can lead to using the wrong key despite the flag being accepted.
Code

bin/burden[R1911-1914]

  	if [[ $gl_ssh_key_file == "" ]]; then
  		echo "  ssh_key: $HOME/.ssh/id_rsa" >> ansible_vars_main.yml
+			echo "  ssh_public_key: $HOME/.ssh/id_rsa.pub" >> ansible_vars_main.yml
  	else
Evidence
Compliance requires that users can supply both a public and private SSH key and that provided values
are accepted/used (not ignored). The CLI flag --ssh_public_key_file is parsed and stored, but in
create_ansible_options() the public key is hardcoded to the default whenever --ssh_key_file is
unset, disregarding any provided --ssh_public_key_file.

Support supplying both public and private SSH keys in Zathras configuration/inputs
bin/burden[1911-1914]
bin/burden[3651-3656]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`--ssh_public_key_file` is accepted by the CLI but is ignored when `--ssh_key_file` is not set, because `create_ansible_options()` always writes the default `ssh_public_key` in that branch.
## Issue Context
Compliance requires that when users supply both public/private key inputs (and specifically when a public key is supplied), the supplied value is not ignored.
## Fix Focus Areas
- bin/burden[1911-1918]
- bin/burden[3651-3656]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines 1911 to 1914
if [[ $gl_ssh_key_file == "" ]]; then
echo " ssh_key: $HOME/.ssh/id_rsa" >> ansible_vars_main.yml
echo " ssh_public_key: $HOME/.ssh/id_rsa.pub" >> ansible_vars_main.yml
else

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. --ssh_public_key_file ignored 📎 Requirement gap ✓ Correctness

When --ssh_key_file is not provided, the code always writes a default ssh_public_key value and
ignores a user-supplied --ssh_public_key_file. This prevents independently specifying the public
key and can lead to using the wrong key despite the flag being accepted.
Agent Prompt
## Issue description
`--ssh_public_key_file` is accepted by the CLI but is ignored when `--ssh_key_file` is not set, because `create_ansible_options()` always writes the default `ssh_public_key` in that branch.

## Issue Context
Compliance requires that when users supply both public/private key inputs (and specifically when a public key is supplied), the supplied value is not ignored.

## Fix Focus Areas
- bin/burden[1911-1918]
- bin/burden[3651-3656]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@sayalibhavsar
Copy link
Contributor Author

When --ssh_key_file is provided but --ssh_public_key_file is not, the ssh_public_key variable was never written to ansible_vars_main.yml. This caused the Terraform template (tfvars.j2) to fail with: 'dict object' has no attribute 'ssh_public_key'. Now it defaults to $HOME/.ssh/id_rsa.pub — matching the behavior when no SSH key is specified at all (line 1913).

uperf with public key
uperf without public key

@sayalibhavsar sayalibhavsar requested review from dvalinrh and kdvalin and removed request for dvalinrh February 27, 2026 19:11
@github-actions
Copy link

PullHero Review

Provider: generativelanguage.googleapis.com Model: gemini-2.0-flash

OK. Here's a review of the changes with a focus on code quality, potential issues, and adherence to project conventions.

Overview

The changes introduce a new ssh_public_key_path variable and associated logic to the Zathras framework. This allows users to explicitly specify the path to the SSH public key file, rather than relying on the default ~/.ssh/id_rsa.pub. This enhances flexibility, particularly when dealing with non-standard key locations or automated key management systems.

Code Quality and Maintainability

  • Variable Definitions: The addition of ssh_public_key_path with a default value of ~/.ssh/id_rsa.pub in vars.tf for aws_create, azure_create and gcp_create_instance roles is well structured.
  • Template Modifications: The modifications in tfvars.j2 and related templates to utilize ssh_public_key_path are straightforward and easy to understand.
  • bin/burden Changes: The changes to bin/burden are logically organized and follow existing patterns for handling command-line arguments and setting variables. The added verify_ssh_public_key_file function is also good practice.
  • Consistency: The changes are consistently applied across different cloud providers (AWS, Azure, GCP), ensuring uniform behavior.

Potential Bugs or Security Issues

  • Default Public Key: The default public key path ~/.ssh/id_rsa.pub might not always be the correct one. While the addition of ssh_public_key_path provides a way to override this, it's important to clearly document that users must provide this if the public key is not in the default location.
  • Key Validation: The verify_ssh_public_key_file function checks for the existence of the file, but not whether it's a valid public key. While the Terraform file() function will likely fail if the contents of the file are invalid, it would be beneficial to add a basic validation step (e.g., checking the file extension or content format) to provide earlier feedback to the user.
  • Security: While not directly introduced by these changes, the reliance on SSH key-based authentication should be carefully considered in the context of overall security. Users should be encouraged to use strong, unique key pairs and to protect their private keys.

Adherence to Project Conventions

  • The changes follow the existing project structure and coding style.
  • The naming conventions for variables and functions are consistent with the rest of the codebase.
  • The use of Terraform templates and Ansible roles aligns with the project's infrastructure-as-code approach.

Documentation Completeness

  • The commit message and PR description should clearly explain the purpose of the changes and how to use the new ssh_public_key_path option.
  • The documentation in docs/command_line_reference.md needs to be updated to reflect the new ssh_public_key_file option. Also, the use of the variable should be documented (e.g., in docs/testing_quickstart.md).

Suggestions

  1. Add documentation: Update docs/command_line_reference.md and other relevant documentation files to describe the new ssh_public_key_file option and its usage. Emphasize the importance of specifying the correct public key path.
  2. Consider Public Key Validation: Add a basic validation step in verify_ssh_public_key_file to check the file extension or content format. This could be a simple regex check.
  3. Update Examples: Provide examples in the documentation and/or README of how to use the new option with different cloud providers and scenarios.

Vote

Vote: +1

Vote: +1

PullHero

@github-actions
Copy link

PullHero Review

Provider: generativelanguage.googleapis.com Model: gemini-2.0-flash

Okay, I've reviewed the proposed changes. The primary goal of this PR seems to be to allow users to explicitly specify the public key file used for SSH authentication, rather than relying on a hardcoded default (~/.ssh/id_rsa.pub). This provides more flexibility, especially when dealing with different key pairs or when the standard location isn't used.

Analysis

  • Code Quality and Maintainability: The changes are relatively straightforward and easy to understand. Adding a new variable and updating the templates to use it is a common pattern.
  • Potential Bugs or Security Issues: No immediate security concerns are apparent. The changes primarily involve specifying a path to a file, not modifying the authentication logic itself. However, it is important to make sure that the path is correctly handled and that the user has appropriate permissions to read the specified public key file.
  • Adherence to Project Conventions: The changes seem to fit within the existing project structure and coding style.
  • Documentation Completeness: The documentation needs to be updated to reflect the new --ssh_public_key_file option. The docs/command_line_reference.md file needs to be updated, and a brief mention in the README.md file might be helpful.

Specific Feedback

  1. Variable Naming: The variable names are consistent and descriptive (e.g., ssh_public_key_path). Good job.
  2. Default Value: The default value for the new variables seems sensible (~/.ssh/id_rsa.pub). It maintains backward compatibility.
  3. Code Duplication: There is some duplication in the admin_ssh_key block within Azure's Terraform files (main_net_p2_sub.tf, main_net_p2_urn.tf, vm_spot_set_sub.tf, vm_spot_set_urn.tf). While minor, consider creating a template snippet or a local variable to avoid this repetition.
  4. Error Handling: There isn't explicit error handling for cases where the specified public key file doesn't exist or is unreadable. While the Terraform file() function should throw an error, it might be worth adding a pre-check within the ansible roles to validate the existence and readability of the file. This would provide a more user-friendly error message.
  5. Documentation: The docs/command_line_reference.md file must be updated to include the new --ssh_public_key_file option, its purpose, and usage. Update README.md with this new option.

Recommendations

  1. Azure Terraform Refactoring (Minor): Refactor the Azure Terraform files to reduce code duplication in the admin_ssh_key block.
  2. Ansible Pre-Check (Optional): Consider adding a task in the Ansible roles to verify the existence and readability of the specified public key file.
  3. Documentation Update (Mandatory): Update docs/command_line_reference.md and README.md to include the --ssh_public_key_file option.

Vote: -1

Vote: -1

PullHero

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow user to supply both public and private SSH key to Zathras

2 participants